use assert_approx_eq::assert_approx_eq;

// A simple macro_rules! that computes Euclidean length of n dimensional vectors.
// Writing norm!(x, 1, 2) might be easier to express and more efficient than
// packing x, 1, and 2 into a Vec and calling a function that computes the length.
macro_rules! norm {
    ($($element:expr),*) => {
        {
            let mut n = 0.0;
            $(
                n += ($element as f64) * ($element as f64);
            )*

            n.sqrt()
        }
    };
}

// Run 'cargo expand' to see the macro expansion.
fn main() {
    let x = -3f64;
    let y = 4f64;

    // sqrt((-3)^2) = 3
    assert_approx_eq!(3f64, norm!(x));
    // sqrt((-3)^2 + 4^2) = 5
    assert_approx_eq!(5f64, norm!(x, y));
    // sqrt(0^2 + 0^2 + 0^2) = 0
    assert_approx_eq!(0f64, norm!(0, 0, 0));
    // sqrt(0.5^2) = 0.5
    assert_approx_eq!(0.5f64, norm!(0.5));
    // sqrt(0.5^2 + (-0.5)^2) = sqrt(0.5) = sqrt(1/2) = 1/sqrt(2)
    assert_approx_eq!(std::f64::consts::FRAC_1_SQRT_2, norm!(0.5, -0.5));
    // sqrt(0.5^2 + (-0.5)^2 + 0.5^2) = sqrt(0.75) = 0.866025404
    assert_approx_eq!(0.8660254037844386f64, norm!(0.5, -0.5, 0.5), 0.000001f64);
    // sqrt(0.5^2 + (-0.5)^2 + 0.5^2) = sqrt(1) = 1
    assert_approx_eq!(1f64, norm!(0.5, -0.5, 0.5, -0.5));
}
